package com.qq.BFMRSE.requestModule;

import java.io.File;
import java.io.IOException;
import java.util.BitSet;
import java.util.List;
import java.util.Stack;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PostMethod;

import com.qq.BFMRSE.encrypt.desEncrypt;
import com.qq.BFMRSE.entity.BloomFilter;
import com.qq.BFMRSE.entity.encryptedIndex;
import com.qq.BFMRSE.entity.indexTree;
import com.qq.BFMRSE.entity.indexTreeNode;
import com.qq.BFMRSE.entity.reposeParam;
import com.qq.BFMRSE.extractWord.SelectHelper;
import com.qq.BFMRSE.extractWord.luIndexUtil;
import com.qq.BFMRSE.extractWord.wordTFAndIDFInfo;
import com.qq.BFMRSE.index.buildIndex;
import com.qq.BFMRSE.index.buildIndexTreeHelper;
import com.qq.BFMRSE.index.indexEncrypted;
import com.qq.BFMRSE.index.indexTreeUpLoad;
import com.qq.BFMRSE.serialize.objectSerializeUtil;
import com.qq.BFMRSE.util.BFConstants;
import com.qq.BFMRSE.util.UserParamManager;

public class addFileModule {
	private String userName;
	private String addFilePath;
	private String indexPath;
	private String skFile;//索引加密秘钥位置
	public String getSkFile() {
		return skFile;
	}
	public void setSkFile(String skFile) {
		this.skFile = skFile;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getAddFilePath() {
		return addFilePath;
	}
	public void setAddFilePath(String addFilePath) {
		this.addFilePath = addFilePath;
	}
	public String getIndexPath() {
		return indexPath;
	}
	public void setIndexPath(String indexPath) {
		this.indexPath = indexPath;
	}
	public addFileModule(){}
	public addFileModule(String userName,String addFilePath,String indexPath,String skFile){
		this.userName=userName;
		this.addFilePath=addFilePath;
		this.indexPath=indexPath;
		this.skFile=skFile;
		System.out.println("test 初始化时skFile="+skFile);
	}
	public reposeParam addFile(String url){
		reposeParam retParam=null;
		String emptyNodesPath=BFConstants.INDEXPATH+File.separator+BFConstants.EMPTYNODES;
		try {
			List<Stack<Integer>> emptyNodePaths=(List<Stack<Integer>>) objectSerializeUtil.deserialize(emptyNodesPath);
			if(emptyNodePaths!=null&&emptyNodePaths.size()>0){
				Stack<Integer>pathStack=emptyNodePaths.get(emptyNodePaths.size()-1);//选取空节点路径集合中最后一个为新节点的插入位置
				retParam=addNewFileExistEmptyNode(url,pathStack);
				if(retParam.getStateCode()==200){
					emptyNodePaths.remove(emptyNodePaths.size()-1);//删除该空节点
					objectSerializeUtil.serialize(emptyNodePaths, emptyNodesPath);
				}
			}else {
				retParam=addNewFile(url);
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return retParam;
	}
	/**
	 * 上传加密的单个文件
	 * @pram url
	 * @return
	 */
	public int upNewFile(String url){
		int stateCode=0;
		File newFile=new File(addFilePath);
		if(newFile.exists()&&!newFile.isDirectory()){
			desEncrypt desEn=new desEncrypt(skFile);
			File tmpDirFile=new File(BFConstants.ENCRYPTFILETEMPDIR);
			if(!tmpDirFile.exists()||!tmpDirFile.isDirectory()){
				tmpDirFile.mkdir();
			}
			String tmpFileName=BFConstants.ENCRYPTFILETEMPDIR+File.separator+SelectHelper.getReFileName(addFilePath);
			//File desFile=new File(tmpDirFile, tmpFileName);
			try {
				desEn.encrypt(newFile, tmpFileName);
				stateCode=upLoadFileModule.upLoadSingleFile(url, addFilePath, userName);
				upLoadFileModule.deleteDir(tmpDirFile);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				
			}
		}
			
		
		return stateCode;
	
	}
	/**
	 * 添加新文件时，不存在空叶子时的操作
	 * @param indexPath
	 * @param filePath
	 * @param url
	 * @param userName
	 * @return
	 * @throws IOException
	 */
	public reposeParam addNewFile(String url) throws IOException
	{
		int stateCode=0;
		boolean flag=true;
		//addNewFileHelper.addWordInfoOper(filePath, indexPath);//更新关键字信息相关操作
		indexEncrypted inSK=readEncryptedSK();
		if(inSK==null){
			flag=false;
		}else {
			String fileName=SelectHelper.getReFileName(addFilePath);
			buildIndex buIndex=new buildIndex(inSK,skFile);
			luIndexUtil.update(indexPath, addFilePath);//更新关键字词频信息
			wordTFAndIDFInfo.update(indexPath,fileName);
			encryptedIndex newFileIndex=buIndex.getaddFileEncryptedIndex(fileName);//得到加密的索引
			JSONObject jObject1=JSONObject.fromObject(newFileIndex);
			String newFileIndexInfo=jObject1.toString();
			String rootPath=BFConstants.INDEXPATH+File.separator+BFConstants.ROOT;
			indexTreeNode root=(indexTreeNode) objectSerializeUtil.deserialize(rootPath);
			indexTree searchTree=new indexTree(root);//反序列化出索引树
			indexTreeNode newFileNode=buildIndexTreeHelper.getNewLeafIndexTree(fileName);//生成新的叶子节点
			indexTreeNode changedNode=searchTree.getChangedNode(searchTree.getRoot());//得到插入新文件的叶子节点位置
			Stack<Integer>pathStack=searchTree.getPathToChangedNode(searchTree.getRoot(),changedNode);//得到从changedNode到根节点的路径
			JSONArray ja=JSONArray.fromObject(pathStack);
			String path=ja.toString();
			indexTreeNode newTempNode=searchTree.getNewNode(changedNode,newFileNode);//新节点为右孩子
			if(changedNode.getParent().getLeft()==changedNode)
			{
				changedNode.getParent().setLeft(newTempNode);
			}
			else {
				changedNode.getParent().setRight(newTempNode);
			}
			newTempNode.setParent(changedNode.getParent());
			changedNode.setParent(newTempNode);
			newFileNode.setParent(newTempNode);//将新的节点加入到二叉搜索树中 
			updateIndexTree(newTempNode);//从newTempNode开始向上更新二叉树
			String newTempNodeInfo=indexTreeUpLoad.getIndexTreeInfo(newTempNode);
	    	String newFileBitsInfo=newFileNode.getBf().getBits().toString();
	    	objectSerializeUtil.serialize(root, rootPath);//将更新后的索引树序列化
			HttpClient httpClient=new HttpClient();
			PostMethod post=new PostMethod(url);
			post.setParameter("userName",userName);
			post.setParameter("fileName", fileName);
			post.setParameter("newFileIndexInfo", newFileIndexInfo);
			post.setParameter("newTempNodeInfo", newTempNodeInfo);
			post.setParameter("path",path);
			post.setParameter("newFileBitsInfo", newFileBitsInfo);
			post.setParameter("flag", "0");//表示不存在空节点
			try {
				httpClient.executeMethod(post);
				stateCode=post.getStatusCode();
			} catch (HttpException e) {
				// TODO Auto-generated catch block
				flag=false;
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				flag=false;
				e.printStackTrace();
			}
		}
		reposeParam retParam=new reposeParam(stateCode,flag);
		return retParam;
	}
	/**
	 * 存在空的叶子节点
	 * @param indexPath
	 * @param filePath
	 * @param url
	 * @param userName
	 * @param emptyNodePaths
	 * @return
	 * @throws IOException
	 */
	public reposeParam addNewFileExistEmptyNode(String url,Stack<Integer>pathStack) throws IOException
	{
		int stateCode=0;
		boolean flag=true;
		indexTreeNode emptyNode=null;
	    //addNewFileHelper.addWordInfoOper(addFilePath, indexPath);//更新关键字信息相关操作
		indexEncrypted inSK=readEncryptedSK();
		if(inSK==null){
			flag=false;
		}else {
			String fileName=SelectHelper.getReFileName(addFilePath);
			buildIndex buIndex=new buildIndex(inSK,skFile);
			luIndexUtil.update(indexPath, addFilePath);//更新关键字词频信息
			wordTFAndIDFInfo.update(indexPath,fileName);
			UserParamManager.update();
			encryptedIndex newFileIndex=buIndex.getaddFileEncryptedIndex(fileName);//得到加密的索引
			JSONObject jObject1=JSONObject.fromObject(newFileIndex);
			String newFileIndexInfo=jObject1.toString();
			String rootPath=BFConstants.INDEXPATH+File.separator+BFConstants.ROOT;
			indexTreeNode root=(indexTreeNode) objectSerializeUtil.deserialize(rootPath);
			//indexTree searchTree=new indexTree(root);//反序列化出索引树
			indexTreeNode newFileNode=buildIndexTreeHelper.getNewLeafIndexTree(fileName);//生成新的叶子节点
			//Stack<Integer>pathStack=emptyNodePaths.get(emptyNodePaths.size()-1);//选取空节点路径集合中最后一个为新节点的插入位置
			JSONArray ja=JSONArray.fromObject(pathStack);
			String path=ja.toString();
			emptyNode=root;//从根节点开始向下寻找空节点
			while(!pathStack.isEmpty())
			{
				int ret=pathStack.pop();
				//如果ret==0，那么向左搜索
				if(ret==0)
				{
					emptyNode=emptyNode.getLeft();
				}
				else {
					emptyNode=emptyNode.getRight();
				}
			}
			emptyNode.setFID(fileName);
			emptyNode.setBf(newFileNode.getBf());
			objectSerializeUtil.serialize(root, rootPath);//将更新后的索引树序列化
			String newFileBitsInfo=newFileNode.getBf().getBits().toString();
			HttpClient httpClient=new HttpClient();
			PostMethod post=new PostMethod(url);
			post.setParameter("userName", userName);
			post.setParameter("fileName", fileName);
			post.setParameter("newFileIndexInfo", newFileIndexInfo);
			post.setParameter("newFileBitsInfo", newFileBitsInfo);
			post.setParameter("path", path);
			post.setParameter("flag", "1");//表示空节点为新文件节点的位置
			try {
				httpClient.executeMethod(post);
				stateCode=post.getStatusCode();
			} catch (HttpException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		reposeParam retParam=new reposeParam(stateCode,flag);
		return retParam;
	}
	public void updateIndexTree(indexTreeNode node)
	{
		indexTreeNode currNode=node;
		indexTreeNode parentNode=new indexTreeNode();
		indexTreeNode otherNode=new indexTreeNode();
		while(currNode.getParent()!=null)
		{
			parentNode=currNode.getParent();
			if(parentNode.getRight()==currNode)
			{
				otherNode=parentNode.getLeft();
			}
			else {
				otherNode=parentNode.getRight();
			}
			BloomFilter tempBf=getNewBloomFilter(currNode.getBf(),otherNode.getBf());
			parentNode.setBf(tempBf);
			currNode=parentNode;
		}
	}
	public BloomFilter getNewBloomFilter(BloomFilter bf1,BloomFilter bf2)
	{
		BloomFilter resultBf=new BloomFilter();
		BitSet tempBitSet=new BitSet();
		int length=bf1.BitsLength();
		for(int i=0;i<length;i++)
		{
			if(bf1.getBits().get(i)==true||bf2.getBits().get(i)==true)
			{
				tempBitSet.set(i, true);
			}
			else {
				tempBitSet.set(i, false);
			}
		}
		resultBf.setBits(tempBitSet);
		return resultBf;
	}
	/**
	 * 仅仅从文件中读取秘钥
	 * @return
	 */
	public indexEncrypted readEncryptedSK()
	{
		String relskFile=skFile+File.separator+BFConstants.SK;
		System.out.println("test skFile:"+skFile);
		indexEncrypted resultSK=null;
		File file=new File(relskFile);
		if(file.exists()&&file.length()!=0)
		{
			try {
				resultSK=(indexEncrypted) objectSerializeUtil.deserialize(relskFile);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return resultSK;
	}
	
}
